package roborally.model;

public enum Orientation {
	UP(0,-1,270),RIGHT(1,0,0),DOWN(0,1,90),LEFT(-1,0,180);

	/**
	 * an integer that contains the difference needed to move a robot in the x direction on a position with this Enum object as orientation.
	 */
	private int dx;
	/**
	 * an integer that contains the difference needed to move a robot in the y direction on a position with this Enum object as orientation.
	 */
	private int dy;
	
	/**
	 * A final static boolean variables introduced for readability: clockwise == true
	 */
	public static final boolean clockwise = true;
	/**
	 * A final static boolean variables introduced for readability: counterclockwise == false
	 */
	public static final boolean counterclockwise = false;

	/**
	 * A variable that contains the angle of this orientation with the x-axis
	 */
	private double angle;
	
	/**
	 * 
	 * @param 	dx
	 * 			the difference over x needed to move a robot on a position with this Enum object as orientation
	 * @param 	dy
	 * 			the difference over y needed to move a robot on a position with this Enum object as orientation
	 */
	Orientation(int dx, int dy, double angle)
	{
		this.dx = dx;
		this.dy = dy;
		this.angle = angle;
	}
	/**
	 * @return returns dx
	 */
	public long getDx() {
		return dx;
	}
	/**
	 * @return returns dy
	 */
	public long getDy() {
		return dy;
	}
	/**
	 * Checks if the given orientation is valid.
	 * @param 	orientation
	 * 			An instance of the Enum Orientation.
	 * @return 	If the orientation instance is effective (if it is not a null reference), then it is an instance of the Enum Orientation and thus is valid and we return true. 
	 * 			Else return false.
	 * 			| result == (orientation != null)
	 */
	public static boolean isValidOrientation(Orientation orientation)
	{
		return orientation != null;
	}
	
	/**
	 * @return returns angle of the orientation
	 */
	public double getAngle() {
		return angle;
	}
	/**
	 * A method that when invoked on an Orientation object, gives the orientation situated clockwise
	 * or counterclockwise from the Orientation object, depending on the parameter
	 * @param clockwise
	 * @return The orientation situated clockwise or counterclockwise from the Orientation
	 * 			|let
	 * 			|	if(clockwise) newIntOrientation = (ordinal() + 1)%4
	 * 			|	else
	 * 			|		newIntOrientation = ordinal() - 1
	 * 			|		if(newIntOrientation < 0) newIntOrientation = 3
	 * 			|in
	 * 			|	result == Orientation.values()[newIntOrientation]
	 */
	public Orientation turn(boolean clockwise) {
		int newIntOrientation;
		if(clockwise)
		{
			newIntOrientation = (this.ordinal() + 1) % 4;
		}
		else //counterclockwise
		{
			newIntOrientation = this.ordinal() - 1;
			if(newIntOrientation < 0) newIntOrientation = 3;
		}
		return Orientation.values()[newIntOrientation];
	}	
	
	/**
	 * returns the orientation for which the position is situated respectively to (0,0),
	 * if this is not in one of the four strict orientations, null is returned.
	 * @param position
	 * @return
	 */
	public static Orientation positionVectorToOrientation(Position position){
		if(position.getX() == 0){
			if(position.getY() > 0) return Orientation.DOWN;
			if(position.getY() < 0) return Orientation.UP;
		}
		if(position.getY() == 0){
			if(position.getX() > 0) return Orientation.RIGHT;
			if(position.getX() < 0) return Orientation.LEFT;
		}
		return null;
	}
}
